<?php
namespace payment;

use Env;

class Wxpay
{
    public $apiurl   = '';
    public $key      = '';
    private $setting = '';
    private $config  = [
        'appid'            => '',
        'mch_id'           => '',
        'device_info'      => '',
        'nonce_str'        => '',
        'sign'             => '',
        'sign_type'        => '',
        'body'             => '',
        'detail'           => '',
        'attach'           => '',
        'out_trade_no'     => '',
        'fee_type'         => '',
        'total_fee'        => '',
        'spbill_create_ip' => '',
        'time_start'       => '',
        'time_expire'      => '',
        'goods_tag'        => '',
        'notify_url'       => '',
        'trade_type'       => '',
        'product_id'       => '',
        'limit_pay'        => '',
        'openid'           => '',
        'scene_info'       => '',
        'out_refund_no'    => '',
        'refund_fee'       => '',
        'refund_fee_type'  => '',
        'refund_desc'      => '',
        'refund_account'   => '',
        'refund_id'        => '',
        //企业转账
        'mch_appid'        => '',
        'mchid'            => '',
        'partner_trade_no' => '',
        'check_name'       => '',
        're_user_name'     => '',
        'amount'           => '',
        'desc'             => '',
        //消息通知
        'touser'           => '',
        'template_id'      => '',
        'url'              => '',
        'miniprogram'      => '',
        'pagepath'         => '',
        'data'             => '',
        'color'            => '',
    ];

    public function __construct($transfer = false)
    {
        global $_G;
        if ($transfer) {
            $this->config['mch_appid'] = $_G['setting']['wxpay_app_id'];
            $this->config['mchid']     = $_G['setting']['wxpay_merchant_id'];
        } else {
            $this->config['appid']  = $_G['setting']['wxpay_app_id'];
            $this->config['mch_id'] = $_G['setting']['wxpay_merchant_id'];
        }
        $this->config['spbill_create_ip'] = request()->ip();
        $this->config['nonce_str']        = random(32);
        $this->key                        = $_G['setting']['wxpay_key'];
    }

    private function curlPost($post = '', $ssl = false)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->apiurl);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        if ($ssl) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //严格校验
            curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLCERT, Env::get('extend_path') . 'payment/weixin/apiclient_cert.pem');
            curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($ch, CURLOPT_SSLKEY, Env::get('extend_path') . 'payment/weixin/apiclient_key.pem');
        }
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
        $reponse = curl_exec($ch);
        curl_close($ch);
        $result = json_decode($reponse, true);
        if (is_array($result) && $result) {
            return $result;
        }
        $result = \simplexml_load_string($reponse, 'SimpleXMLElement', LIBXML_NOCDATA);
        return json_decode(json_encode($result), true) ?: [];
    }

    private function array_to_xml()
    {
        $this->config['sign'] = $this->sign(array_filter($this->config));
        $param                = array_filter($this->config);
        ksort($param);
        $str = '<xml>' . PHP_EOL;
        foreach ($param as $k => $v) {
            $str .= '<' . $k . '>';
            if (is_array($v)) {
                $str .= '<![CDATA[';
                $str .= json_encode($v);
                $str .= ']]>';
            } else {
                $str .= $v;
            }
            $str .= '</' . $k . '>';
            $str .= PHP_EOL;
        }
        $str .= '</xml>';
        return $str;
    }

    public function sign($param = [])
    {
        ksort($param);
        $str = '';
        foreach ($param as $k => $v) {
            $str .= $k . '=' . $v . '&';
        }
        return strtoupper(md5(trim($str, '&') . '&key=' . $this->key));
    }

    public function verify($data, $sign)
    {
        unset($data['sign']);
        if ($this->sign($data) === $sign) {
            return true;
        }
        return false;
    }

    public function setConfig($config)
    {
        $this->config = array_merge($this->config, $config);
        return $this;
    }

    public function setOrder($param)
    {
        foreach ($param as $k => $v) {
            switch ($k) {
                case 'order_id':
                    $this->config['out_trade_no'] = $v;
                    break;
                case 'price':
                    $this->config['total_fee'] = $v * 100;
                    break;
                case 'subject':
                    $this->config['body'] = $v;
                    break;
                case 'body':
                    $this->config['detail'] = $v;
                    break;
                case 'create_ip':
                    $this->config['spbill_create_ip'] = $v != '::1' ? $v : '0.0.0.0';
                    break;
                case 'refund_price':
                    $this->order['refund_fee'] = $v;
                    break;
                case 'refund_order_id':
                    $this->order['out_refund_no'] = $v;
                    break;

                default:
                    if (isset($this->config[$k])) {
                        $this->config[$k] = $v;
                    }
                    break;
            }
        }
        return $this;
    }

    public function unifiedOrder()
    {
        $this->apiurl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
        return $this->curlPost($this->array_to_xml());
        return $result;
    }

    public function queryOrder()
    {
        $this->apiurl = 'https://api.mch.weixin.qq.com/pay/orderquery';
        $result       = $this->curlPost($this->array_to_xml());
        return $result;
    }

    public function closeOrder()
    {
        $this->apiurl = 'https://api.mch.weixin.qq.com/pay/closeorder';
        return $this->curlPost($this->array_to_xml());
    }

    public function refundOrder()
    {
        $this->apiurl = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
        return $this->curlPost($this->array_to_xml());
    }

    public function queryRefundOrder()
    {
        $this->apiurl = 'https://api.mch.weixin.qq.com/pay/refundquery';
        return $this->curlPost($this->array_to_xml());
    }

    public function transfer()
    {
        $this->apiurl = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers';
        return $this->curlPost($this->array_to_xml(), true);
    }

    public function queryTransfer()
    {
        $this->apiurl = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo';
        return $this->curlPost($this->array_to_xml(), true);
    }

    public function notification($post)
    {
        $access       = file_get_contents('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $this->setting['param']['appid'] . '&secret=' . $this->setting['param']['secret']);
        $access       = json_decode($access, true);
        $this->apiurl = 'https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=' . $access['access_token'];
        return $this->curlPost($post);
    }
}
